//: C25:InnerClassIdiom.cpp
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 1999
// Copyright notice in Copyright.txt
// Example of the "inner class" idiom
#include <iostream>
#include <string>
using namespace std;

class Poingable
{
public:
    virtual void poing() = 0;
};

void callPoing(Poingable& p)
{
    p.poing();
}

class Bingable
{
public:
    virtual void bing() = 0;
};

void callBing(Bingable& b)
{
    b.bing();
}

class Outer
{
    string name;
    // Define one inner class:
    class Inner1;
    friend class Outer::Inner1;
    class Inner1 : public Poingable
    {
        Outer* parent;
    public:
        Inner1(Outer* p) : parent(p) {}
        void poing() {
            cout << "poing called for "
                 << parent->name << endl;
            // Accesses data in the outer class object
        }
    } inner1;
    // Define a second inner class:
    class Inner2;
    friend class Outer::Inner2;
    class Inner2 : public Bingable
    {
        Outer* parent;
    public:
        Inner2(Outer* p) : parent(p) {}
        void bing() {
            cout << "bing called for "
                 << parent->name << endl;
        }
    } inner2;
public:
    Outer(const string& nm) : name(nm),
            inner1(this), inner2(this) {}
    // Return reference to interfaces
    //  implemented by the inner classes:
    operator Poingable&() {
        return inner1;
    }
    operator Bingable&() {
        return inner2;
    }
};

int main()
{
    Outer x("Ping Pong");
    // Like upcasting to multiple base types!:
    callPoing(x);
    callBing(x);
} ///:~
